#include "rtp-param.h"
#include "rtp-internal.h"
#include "rtp-packet.h"

enum {
    RTP_SENDER = 1,   /// send RTP packet
    RTP_RECEIVER = 2, /// receive RTP packet
};

double rtcp_interval(int members, int senders, double rtcp_bw, int we_sent, double avg_rtcp_size, int initial);

void *rtp_create(struct rtp_event_t *handler, void *param, uint32_t ssrc, uint32_t timestamp, int frequence,
                 int bandwidth, int sender)
{
    struct rtp_context *ctx;

    ctx = (struct rtp_context *)calloc(1, sizeof(*ctx));
    if (!ctx)
        return NULL;

    ctx->self = rtp_member_create(ssrc);
    ctx->members = rtp_member_list_create();
    ctx->senders = rtp_member_list_create();
    if (!ctx->self || !ctx->members || !ctx->senders) {
        rtp_destroy(ctx);
        return NULL;
    }

    ctx->self->rtp_clock = rtpclock();
    ctx->self->rtp_timestamp = timestamp;
    rtp_member_list_add(ctx->members, ctx->self);

    memcpy(&ctx->handler, handler, sizeof(ctx->handler));
    ctx->cbparam = param;
    ctx->rtcp_bw = (int)(bandwidth * RTCP_BANDWIDTH_FRACTION);
    ctx->avg_rtcp_size = 0;
    ctx->frequence = frequence;
    ctx->role = sender ? RTP_SENDER : RTP_RECEIVER;
    ctx->init = 1;
    return ctx;
}

int rtp_destroy(void *rtp)
{
    struct rtp_context *ctx = (struct rtp_context *)rtp;

    if (ctx->members)
        rtp_member_list_destroy(ctx->members);
    if (ctx->senders)
        rtp_member_list_destroy(ctx->senders);
    if (ctx->self)
        rtp_member_release(ctx->self);
    free(ctx);
    return 0;
}

int rtp_onsend(void *rtp, const void *data, int bytes)
{
    //	time64_t ntp;
    struct rtp_packet_t pkt;
    struct rtp_context *ctx = (struct rtp_context *)rtp;

    assert(RTP_SENDER == ctx->role);
    ctx->role = RTP_SENDER;
    // don't need add self to sender list
    // rtp_member_list_add(ctx->senders, ctx->self);

    if (0 != rtp_packet_deserialize(&pkt, data, bytes))
        return -1; // packet error

    ctx->self->rtp_clock = rtpclock();
    ctx->self->rtp_timestamp = pkt.rtp.timestamp; // RTP timestamp
    ctx->self->rtp_bytes += pkt.payloadlen;
    ctx->self->rtp_packets += 1;
    return 0;
}

int rtp_onreceived(void *rtp, const void *data, int bytes)
{
    struct rtp_context *ctx = (struct rtp_context *)rtp;
    return rtcp_input_rtp(ctx, data, bytes);
}

int rtp_onreceived_rtcp(void *rtp, const void *rtcp, int bytes)
{
    struct rtp_context *ctx = (struct rtp_context *)rtp;
    return rtcp_input_rtcp(ctx, rtcp, bytes);
}

int rtp_rtcp_report(void *rtp, void *data, int bytes)
{
    int n;
    struct rtp_context *ctx = (struct rtp_context *)rtp;

//#pragma message("update we_sent flag")
    // don't send packet in 2T
    // ctx->role = RTP_RECEIVER

    if (RTP_SENDER == ctx->role) {
        // send RTP in 2T
        n = rtcp_sr_pack(ctx, (uint8_t *)data, bytes);
    } else {
        assert(RTP_RECEIVER == ctx->role);
        n = rtcp_rr_pack(ctx, (uint8_t *)data, bytes);
    }

    // compound RTCP Packet
    if (n < bytes) {
        n += rtcp_sdes_pack(ctx, (uint8_t *)data + n, bytes - n);
    }

    ctx->init = 0;
    return n;
}

int rtp_rtcp_bye(void *rtp, void *data, int bytes)
{
    struct rtp_context *ctx = (struct rtp_context *)rtp;
    return rtcp_bye_pack(ctx, (uint8_t *)data, bytes);
}

int rtp_rtcp_app(void *rtp, void *data, int bytes, const char name[4], const void *app, int len)
{
    struct rtp_context *ctx = (struct rtp_context *)rtp;
    return rtcp_app_pack(ctx, (uint8_t *)data, bytes, name, app, len);
}

int rtp_rtcp_rtpfb(void *rtp, void *data, int bytes, enum rtcp_rtpfb_type_t id, const rtcp_rtpfb_t *rtpfb)
{
    struct rtp_context *ctx = (struct rtp_context *)rtp;
    return rtcp_rtpfb_pack(ctx, (uint8_t *)data, bytes, id, rtpfb);
}

int rtp_rtcp_psfb(void *rtp, void *data, int bytes, enum rtcp_psfb_type_t id, const rtcp_psfb_t *psfb)
{
    struct rtp_context *ctx = (struct rtp_context *)rtp;
    return rtcp_psfb_pack(ctx, (uint8_t *)data, bytes, id, psfb);
}

int rtp_rtcp_xr(void *rtp, void *data, int bytes, enum rtcp_xr_type_t id, const rtcp_xr_t *xr)
{
    struct rtp_context *ctx = (struct rtp_context *)rtp;
    return rtcp_xr_pack(ctx, (uint8_t *)data, bytes, id, xr);
}

int rtp_rtcp_interval(void *rtp)
{
    double interval;
    struct rtp_context *ctx = (struct rtp_context *)rtp;
    interval = rtcp_interval(rtp_member_list_count(ctx->members),
                             rtp_member_list_count(ctx->senders) + ((RTP_SENDER == ctx->role) ? 1 : 0), ctx->rtcp_bw,
                             (ctx->self->rtp_clock + 2 * RTCP_REPORT_INTERVAL * 1000 > rtpclock()) ? 1 : 0,
                             ctx->avg_rtcp_size, ctx->init);

    return (int)(interval * 1000);
}

const char *rtp_get_cname(void *rtp, uint32_t ssrc)
{
    struct rtp_member *member;
    struct rtp_context *ctx = (struct rtp_context *)rtp;
    member = rtp_member_list_find(ctx->members, ssrc);
    return member ? (char *)member->sdes[RTCP_SDES_CNAME].data : NULL;
}

const char *rtp_get_name(void *rtp, uint32_t ssrc)
{
    struct rtp_member *member;
    struct rtp_context *ctx = (struct rtp_context *)rtp;
    member = rtp_member_list_find(ctx->members, ssrc);
    return member ? (char *)member->sdes[RTCP_SDES_NAME].data : NULL;
}

int rtp_set_info(void *rtp, const char *cname, const char *name)
{
    struct rtp_context *ctx = (struct rtp_context *)rtp;
    rtp_member_setvalue(ctx->self, RTCP_SDES_CNAME, (const uint8_t *)cname, (int)strlen(cname));
    rtp_member_setvalue(ctx->self, RTCP_SDES_NAME, (const uint8_t *)name, (int)strlen(name));
    return 0;
}
